package com.gitee.kenewstar.migration.service.migration;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.gitee.kenewstar.migration.entity.Lov;
import com.gitee.kenewstar.migration.entity.LovTl;
import com.gitee.kenewstar.migration.entity.LovValue;
import com.gitee.kenewstar.migration.entity.LovValueTl;
import com.gitee.kenewstar.migration.entity.LovViewHeader;
import com.gitee.kenewstar.migration.entity.LovViewHeaderTl;
import com.gitee.kenewstar.migration.entity.LovViewLine;
import com.gitee.kenewstar.migration.entity.LovViewLineTl;
import com.gitee.kenewstar.migration.entity.CommonResult;
import com.gitee.kenewstar.migration.service.LovService;
import com.gitee.kenewstar.migration.util.ProxySelf;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author kenewstar
 */
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class LovMigrationServiceImpl implements LovMigrationService, ProxySelf<LovMigrationService> {

    private final LovService lovService;

    @Override
    public List<CommonResult> lovMigration(List<String> lovCodeList, Long tenantId) {

        // 查询所有值集
        final List<Lov> lovList = this.lovService.devSelectLov(lovCodeList, tenantId);
        if (CollUtil.isEmpty(lovList)) {
            return Collections.emptyList();
        }

        // 值集多语言
        QueryWrapper<LovTl> wrapper = new QueryWrapper<>();
        wrapper.in("lov_id", lovList.stream().map(Lov::getLovId).collect(Collectors.toList()));
        final List<LovTl> lovTls1 = this.lovService.devSelectTl(wrapper);
        final Map<Long, List<LovTl>> lovTlListMap = lovTls1.stream().collect(Collectors.groupingBy(LovTl::getLovId));

        QueryWrapper<LovValue> valueQueryWrapper = new QueryWrapper<>();
        valueQueryWrapper.in("lov_id", lovList.stream().map(Lov::getLovId).collect(Collectors.toList()));
        final List<LovValue> lovValueList = this.lovService.devSelectLovValue(valueQueryWrapper);
        final Map<Long, List<LovValue>> lovValueListMap = lovValueList.stream().collect(Collectors.groupingBy(LovValue::getLovId));

        QueryWrapper<LovValueTl> lovValueTlQueryWrapper = new QueryWrapper<>();
        Map<Long, List<LovValueTl>> lovValueTlsMap;
        final List<Long> lovValueIds = lovValueList.stream().map(LovValue::getLovValueId).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(lovValueIds)) {
            lovValueTlQueryWrapper.in("lov_value_id", lovValueIds);
            final List<LovValueTl> lovValueTls = this.lovService.devSelectLovValueTl(lovValueTlQueryWrapper);
            lovValueTlsMap = lovValueTls.stream().collect(Collectors.groupingBy(LovValueTl::getLovValueId));
        } else {
            lovValueTlsMap = new HashMap<>(0);
        }

        List<CommonResult> results = new ArrayList<>(lovList.size());
        lovList.forEach(v -> {
            try {
                this.self().singleLovMigration(v, lovTlListMap, lovValueListMap, lovValueTlsMap);
                results.add(CommonResult.create(true).setLovCode(v.getLovCode()));
            } catch (Exception e) {
                results.add(CommonResult.create(false).setLovCode(v.getLovCode()).setErrorMsg(e.getMessage()));
                e.printStackTrace();
            }
        });
        return results;
    }

    @Override
    @DS("uat")
    @Transactional(rollbackFor = Exception.class)
    public void singleLovMigration(Lov lov, Map<Long, List<LovTl>> lovTlListMap,
                                   Map<Long, List<LovValue>> lovValueListMap,
                                   Map<Long, List<LovValueTl>> lovValueTlsMap) {
        Long srcLovId = lov.getLovId();
        List<LovTl> list = lovTlListMap.get(srcLovId);
        lov.setLovId(null);
        lovService.uatInsertLov(ListUtil.toList(lov));
        list.forEach(v -> v.setLovId(lov.getLovId()));
        lovService.uatInsertLovTl(list);

        // 值集列表
        List<LovValue> lovValues = lovValueListMap.get(srcLovId);
        if (CollUtil.isNotEmpty(lovValues)) {
            lovValues.forEach(v -> v.setLovId(lov.getLovId()));
            lovValues.forEach(v -> v.setSrcLovValueId(v.getLovValueId()));
            lovValues.forEach(v -> v.setLovValueId(null));
            lovService.uatInsertLovValue(lovValues);
        }
        if (CollUtil.isEmpty(lovValues)) {
            return;
        }
        List<LovValueTl> lovValueTlList = new ArrayList<>(10);
        // 多语言列表
        for (LovValue lovValue : lovValues) {
            List<LovValueTl> valueTls = lovValueTlsMap.get(lovValue.getSrcLovValueId());
            valueTls.forEach(v -> v.setLovValueId(lovValue.getLovValueId()));
            lovValueTlList.addAll(valueTls);
        }
        this.lovService.uatInsertLovValueTl(lovValueTlList);
    }

    @Override
    public List<CommonResult> lovViewMigration(List<String> lovViewCodeList, Long tenantId) {

        // 查询视图
        final List<LovViewHeader> headerList = this.lovService.devSelectLovHeader(lovViewCodeList, tenantId);
        if (CollUtil.isEmpty(headerList)) {
            return Collections.emptyList();
        }

        final List<Lov> devLovList = this.lovService.devSelectLov(headerList.stream().map(LovViewHeader::getLovId).collect(Collectors.toList()));
        final List<Lov> uatLovList = this.lovService.uatSelectLov(devLovList.stream().map(Lov::getLovCode).collect(Collectors.toList()));
        Map<Long, Long> devUatLovMap = new HashMap<>(uatLovList.size());

        // dev lovId -> uat lovId
        Map<String, Long> uatLovIdMap = new HashMap<>(uatLovList.size());
        uatLovList.forEach(x -> uatLovIdMap.put(x.getLovCode() + "," + x.getTenantId(), x.getLovId()));
        devLovList.forEach(x -> devUatLovMap.put(x.getLovId(), uatLovIdMap.get(x.getLovCode() + "," + x.getTenantId())));

        QueryWrapper<LovViewHeaderTl> headerTlQueryWrapper = new QueryWrapper<>();
        headerTlQueryWrapper.in("view_header_id", headerList.stream().map(LovViewHeader::getViewHeaderId).collect(Collectors.toList()));
        final List<LovViewHeaderTl> lovViewHeaderTls = this.lovService.devSelectLovHeaderTl(headerTlQueryWrapper);
        final Map<Long, List<LovViewHeaderTl>> headerTlsMap = lovViewHeaderTls.stream().collect(Collectors.groupingBy(LovViewHeaderTl::getViewHeaderId));

        QueryWrapper<LovViewLine> lineQueryWrapper = new QueryWrapper<>();
        lineQueryWrapper.in("view_header_id", headerList.stream().map(LovViewHeader::getViewHeaderId).collect(Collectors.toList()));
        final List<LovViewLine> lineList = this.lovService.devSelectLovLine(lineQueryWrapper);
        final Map<Long, List<LovViewLine>> lineMap = lineList.stream().collect(Collectors.groupingBy(LovViewLine::getViewHeaderId));

        final List<Long> viewLineIds = lineList.stream().map(LovViewLine::getViewLineId).collect(Collectors.toList());
        final Map<Long, List<LovViewLineTl>> lovViewLineTlsMap;
        if (CollUtil.isNotEmpty(viewLineIds)) {
            QueryWrapper<LovViewLineTl> lineTlQueryWrapper = new QueryWrapper<>();
            lineTlQueryWrapper.in("view_line_id", viewLineIds);
            final List<LovViewLineTl> lovViewLineTls = this.lovService.devSelectLovLineTl(lineTlQueryWrapper);
            lovViewLineTlsMap = lovViewLineTls.stream().collect(Collectors.groupingBy(LovViewLineTl::getViewLineId));
        } else {
            lovViewLineTlsMap = new HashMap<>(0);
        }


        List<CommonResult> results = new ArrayList<>();
        headerList.forEach(x -> {
            try {
                this.self().singleLovViewMigration(x, devUatLovMap, headerTlsMap, lineMap, lovViewLineTlsMap);
                results.add(CommonResult.create(true).setLovViewCode(x.getViewCode()));
            } catch (Exception e) {
                results.add(CommonResult.create(false).setLovViewCode(x.getViewCode()).setErrorMsg(e.getMessage()));
                e.printStackTrace();
            }
        });
        return results;

    }

    @Override
    @DS("uat")
    @Transactional(rollbackFor = Exception.class)
    public void singleLovViewMigration(LovViewHeader header,
                                       Map<Long, Long> devUatLovMap,
                                       Map<Long, List<LovViewHeaderTl>> headerTlsMap,
                                       Map<Long, List<LovViewLine>> lineMap,
                                       Map<Long, List<LovViewLineTl>> lovViewLineTlsMap) {
        Long devHeaderId = header.getViewHeaderId();

        header.setViewHeaderId(null);
        Long uatLovId = devUatLovMap.get(header.getLovId());
        Assert.notNull(uatLovId, "目标环境值集不存在");
        header.setLovId(uatLovId);
        this.lovService.uatInsertLovHeader(ListUtil.toList(header));

        // 插入多语言数据
        final List<LovViewHeaderTl> headerTls = headerTlsMap.get(devHeaderId);
        headerTls.forEach(v -> v.setViewHeaderId(header.getViewHeaderId()));
        this.lovService.uatInsertLovHeaderTl(headerTls);

        // 插入视图行数据
        final List<LovViewLine> viewLines = lineMap.get(devHeaderId);
        if (CollUtil.isEmpty(viewLines)) {
            return;
        }
        viewLines.forEach(v -> v.setDevViewLineId(v.getViewLineId()));
        viewLines.forEach(v -> v.setLovId(header.getLovId()));
        viewLines.forEach(v -> v.setViewLineId(null));
        viewLines.forEach(v -> v.setViewHeaderId(header.getViewHeaderId()));
        this.lovService.uatInsertLovLine(viewLines);

        List<LovViewLineTl> list = new ArrayList<>(10);
        for (LovViewLine viewLine : viewLines) {
            List<LovViewLineTl> viewLineTls = lovViewLineTlsMap.get(viewLine.getDevViewLineId());
            viewLineTls.forEach(v -> v.setViewLineId(viewLine.getViewLineId()));
            list.addAll(viewLineTls);
        }
        this.lovService.uatInsertLovLineTl(list);
    }

    @Override
    public List<CommonResult> excelLovMigration(List<Lov> lovList) {
        final List<Lov> hasTenantData = lovList.stream().filter(x -> Objects.nonNull(x.getTenantId())).collect(Collectors.toList());
        final List<String> noTenantData = lovList.stream()
                .filter(x -> Objects.isNull(x.getTenantId()))
                .map(Lov::getLovCode)
                .collect(Collectors.toList());

        final Map<Long, List<Lov>> listMap = hasTenantData.stream().collect(Collectors.groupingBy(Lov::getTenantId));
        final List<CommonResult> list = noTenantData.isEmpty() ? new ArrayList<>(10) : this.self().lovMigration(noTenantData, null);

        listMap.forEach((tenantId, lovList1) -> {
            final List<String> codes = lovList1.stream().map(Lov::getLovCode).collect(Collectors.toList());
            list.addAll(this.self().lovMigration(codes, tenantId));
        });
        return list;
    }

    @Override
    public List<CommonResult> excelLovViewMigration(List<LovViewHeader> viewHeaderList) {
        final List<LovViewHeader> hasTenantData = viewHeaderList.stream().filter(x -> Objects.nonNull(x.getTenantId())).collect(Collectors.toList());
        final List<String> noTenantData = viewHeaderList.stream()
                .filter(x -> Objects.isNull(x.getTenantId()))
                .map(LovViewHeader::getViewCode)
                .collect(Collectors.toList());

        final Map<Long, List<LovViewHeader>> listMap = hasTenantData.stream().collect(Collectors.groupingBy(LovViewHeader::getTenantId));
        final List<CommonResult> list = noTenantData.isEmpty() ? new ArrayList<>(10) : this.self().lovViewMigration(noTenantData, null);

        listMap.forEach((tenantId, viewHeaders) -> {
            final List<String> codes = viewHeaders.stream().map(LovViewHeader::getViewCode).collect(Collectors.toList());
            list.addAll(this.self().lovViewMigration(codes, tenantId));
        });
        return list;
    }
}
